<?php


namespace App\Console\Commands;


use Illuminate\Console\Command;
use Illuminate\Support\Str;

//php artisan make:code
//api_class_name api的控制器  admin_class_name  admin控制器  demo_table 表面


class CodeGeneration  extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    //class_name = api@dd/rrr|admin@rrr
    protected $signature = 'generation:code {class_name?} {dir?} {m?}  {--table_name=} {--model_dir=}  {--is_del=}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '批量生成文件';
    protected $tablename =  null;



    protected $filelist = [];

    protected $replace =[
        'name_space'  => '{{name_space}}',
        'class_name'  => '{{class_name}}',
        'associate_path'  => '{{associate_path}}',
        'associate_name'  => '{{associate_name}}',
        'fieldset'  => '{{fieldset}}',
        'module_name'=>'{{module_name}}',
        'controller'=>'{{controller}}',
        'table_name'=>'{{table_name}}',

    ];
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();

        $this->filelist = [
//                    php artisan generation:code ehr_staff_social_reduces staff  --model_dir=staff --is_del=1
//                    php artisan generation:code ehr_staff_social_adds staff  --model_dir=staff
//                    php artisan generation:code ehr_staff_social_increase_or_decrease staff  --model_dir=staff
//                    php artisan generation:code ehr_staff_social_month_pay_logs staff  --model_dir=staff
//                    php artisan generation:code ehr_staff_social_month_plan_logs staff  --model_dir=staff
//                    php artisan generation:code ehr_staff_social_plan_details staff  --model_dir=staff
//                    php artisan generation:code ehr_staff_user_leave_job staff Admin  --model_dir=staff

//                    php artisan generation:code ehr_social_area social  --model_dir=social
//                    php artisan generation:code ehr_social_plan_details social  --model_dir=social
//                    php artisan generation:code ehr_social_plans social  --model_dir=social
//                    php artisan generation:code ehr_socials social  --model_dir=social
        ];
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {

        $m = $this->argument('m');
        $class_name = $this->argument('class_name');
        $dir = $this->argument('dir');
        $table_name = $this->option('table_name');
        $m  = empty($m) ?  ['Api','Admin','Master'] : [Str::studly($m)];           //沒有就全部生成
        $dir  = empty($dir ) ?  [] : explode("/",$dir);         //转数组

        $table_name = empty($table_name) ? $class_name : $table_name;
        $this->tablename = $table_name;

        if(!empty($class_name)){
            //生成文件目录
            foreach ($m as $k){
                $this->filelist['Controller'][$k] = $this->createFileDir($dir,$class_name);
                $this->filelist['Service'][$k] =$this->createFileDir($dir,$class_name);
                $this->filelist['Request'][$k] =$this->createFileDir($dir,$class_name);
                $this->filelist['Manager'][$k] = $this->createFileDir($dir,$class_name);
//                $this->filelist['Model'][$k] = $this->createFileDir($dir,$class_name);
//                $this->filelist['View'][Str::snake(lcfirst($k))] =$this->createFileDir($dir,$class_name,true);
            }
        }

        if(!empty($table_name)){
            $this->filelist['Model'] = [$table_name];
        }

        $this->createHandle();
        //

    }


    /** 创建文件入口 */
    protected function createHandle()
    {
        $output = [];

        foreach ($this->filelist as $appendSuffix =>$list){
            switch ($appendSuffix){
                case 'Controller':
                    $this->createCommand($list, $appendSuffix, 'Http'.DIRECTORY_SEPARATOR.'Controllers');
                    break;
                case 'Service':
                    $this->createCommand($list, $appendSuffix, 'Services');
                    break;
                case 'Manager':
                    $this->createCommand($list, $appendSuffix, 'Managers');
                    break;
                case 'Request':
                    $this->createCommand($list, $appendSuffix, 'Http'.DIRECTORY_SEPARATOR.'Requests');
                    break;
                case "Model":
                    $this->createCommand($list, $appendSuffix, '');
                    break;
                case "View":
                    $this->createCommand($list, $appendSuffix, '');
                    break;
                default:
                    foreach ($list as $command) {
                        $command = 'php artisan make:' . strtolower($appendSuffix) . ' ' . $command;
                        $this->execSystem($command, $output);
                    }
                    foreach ((array)$output as $string) {
                        $this->info($string);
                    }
            }
        }
    }

    /**
     * 生成目录数组
     * @param $dir
     * @param $file
     * @param false $is_lower
     * @return array
     */
    public function createFileDir($dir,$file,$is_lower=false){
            if(empty($dir)){
                return $file;
            }
        $key = array_shift($dir);
        $key =   $is_lower ? Str::snake(lcfirst($key)):  Str::studly($key);
        return [$key =>$this->createFileDir($dir,$file)];

    }

    /**
     * Get the stub file for the generator.
     *
     * @return string
     */
    protected function getStub( $name )
    {
        return  file_get_contents(dirname(dirname(__FILE__)) . '/Template/'.strtolower($name).'.template');
    }

    /** 模板生成 */
    protected function createStub($template, $replace, $path){
        //检查目录
        if ( $this->option('is_del')){
            @unlink($path);
            return null;
        }

        if(! file_exists($path)){
            @make_dir(dirname($path));
            //替换变量
            $source = str_replace(array_keys($replace), array_values($replace), $template);

            return file_put_contents($path,$source);
        }
        return null;
    }

    /** 创建Base 基类 */
    protected function createBase($appendSuffix, $path){

        $template = $this->getStub('base'.strtolower($appendSuffix));

        if($this->createStub($template, [],
            app_path($path) .DIRECTORY_SEPARATOR . 'Base' . $appendSuffix.'.php')){
            $this->info( 'Base' . $appendSuffix . '添加成功');
        } else {
            $this->error( 'Base' . $appendSuffix . '添加失败');
        }
    }



    /** 生成指令 */
    protected function createCommand($list, $appendSuffix, $path)
    {
        foreach($list as $key => $command){

            if(!is_numeric($key)){
                $dir =  $path . DIRECTORY_SEPARATOR . Str::studly($key);
            }else{
                $dir = $path;
            }

            if(is_array($command)){
                $this->createCommand($command, $appendSuffix, $dir);
            }else{
                switch ($appendSuffix){
                    case "Controller":

                    case 'Service':

                    case "Manager":

                    case 'Request':
                        $this->createFile(Str::studly($command), $appendSuffix, $dir);
                        break;
                    case "View":
                        $this->createViewFile(Str::studly($command),  $dir);
                        break;
                    case "Model":

                        $model = empty($this->tablename) ? $command : $this->tablename ;
                        $model = Str::snake($model);
                        if(!empty($model)){
                            if($this->option("model_dir")){
                                $dir = str_replace( '\\',DIRECTORY_SEPARATOR,  $this->option("model_dir"));
                            }
                            $command = 'php artisan create:models '.$model . " " . $dir;
                            $this->execSystem($command,$output);
                        }
                        break;
                }

            }
        }
    }

    /** 创建文件 */
    protected function createFile($controller, $appendSuffix, $path)
    {

        $controller = $this->filter($controller);
        $path = trim($path, DIRECTORY_SEPARATOR);
        //类名
        $className = class_basename($controller) . $appendSuffix;

        $model = empty($this->tablename) ? $controller :  $this->filter($this->tablename) ;
        $model = Str::studly($model);
        //文件路径
        $filePath = app_path($path) . DIRECTORY_SEPARATOR . $controller . $appendSuffix . '.php';
        //文件目录路径
        $dirPath = dirname($filePath);

        //命名空间
        $nameSpace = str_replace(DIRECTORY_SEPARATOR, '\\', str_replace(app_path(), 'App', $dirPath));

        //取$associateName
        switch ($appendSuffix) {
            case "Controller":
                $associateName = class_basename($controller) .'Service';
                $associatePath =  str_replace('App\\Http\\Controllers\\', '', $nameSpace);
                break;
            case 'Service':
                $associatePath =   str_replace('App\\Services\\', '', $nameSpace);
                $associateName = class_basename($controller) .'Manager';
                break;
            case 'Manager':
//                $associatePath =   str_replace('App\\Managers\\', '', $nameSpace);
                $model_dir = $this->option("model_dir");
                $associatePath =  empty($model_dir) ? "" : implode(DIRECTORY_SEPARATOR, array_map([Str::class,'studly'], explode(DIRECTORY_SEPARATOR, $model_dir)));;
                $associateName = class_basename($model) .'Model';
                break;
            case 'Requests':
                $associatePath =   str_replace('App\\Http\\Requests\\', '', $nameSpace);
                $associateName = class_basename($controller) .'Request';
                break;
            case 'Model':
                $associatePath =   str_replace('App\\Models\\', '', $nameSpace);
                $associateName = class_basename($model) .'Model';
                break;
            default:
                $associateName = '';
                $associatePath = '';
        }
        $module_name = empty($associatePath) ? $associatePath : explode('\\',$associatePath)[0];
        $associatePath = empty($associatePath) ? $associatePath :  $associatePath.'\\';
        if(empty($template)){
            $template = $this->getStub(strtolower($appendSuffix));
        }

        $result = $this->createStub($template, [
            $this->replace['class_name'] => $className,
            $this->replace['name_space'] => $nameSpace,
            $this->replace['associate_path'] => $associatePath,
            $this->replace['associate_name'] => $associateName,
            $this->replace['module_name'] => $module_name,
            $this->replace['controller'] => $controller,


        ], $filePath);
        if ($result) {
            $this->info($className . '添加成功');
        } else {
            $this->error($className . '添加失败');
        }
    }

    /** 执行命令 */
    protected function execSystem($command, &$output = null)
    {
        if(system($command,$output)){
            $this->info($command . '添加成功');
        } else {
            $this->error($command . '添加失败');
        }
    }

    /** 创建视图模板 */
    protected function createViewFile($name,  $dir)
    {
        $view = $this->filter($name);
        $name = Str::snake($name);
        $path = 'views';
        if(!empty($dir)){

            $path .= DIRECTORY_SEPARATOR . trim($dir, DIRECTORY_SEPARATOR);
        }
        $path .=  DIRECTORY_SEPARATOR . trim($view, DIRECTORY_SEPARATOR) ;
        $path = implode(DIRECTORY_SEPARATOR, array_map([Str::class, 'snake'], explode(DIRECTORY_SEPARATOR, $path)));
        //文件路径
        $indexPath = resource_path($path) . DIRECTORY_SEPARATOR .'index.blade.php';
        $formPath = resource_path($path) . DIRECTORY_SEPARATOR .'form.blade.php';
        $indexTemplate = $this->getTemplate('index', $name);
        if(
        ! $this->createStub( $this->getStub('view_index'), [
            $this->replace['fieldset'] => $indexTemplate,
        ], $indexPath)
        ){
            $this->error( $name . 'index添加失败');
        }
        $formTemplate = $this->getTemplate('form', $name);
        if(
        ! $this->createStub( $this->getStub('view_form'), [
            $this->replace['fieldset'] => $formTemplate,
        ], $formPath)){
            $this->error( $name . 'form添加失败');
        }
        $this->info( $name. 'View添加完成');
    }



    //过滤名称
    protected  function filter($name){
        $prefix = config("database.connections.mysql.prefix");
        $prefix = Str::studly($prefix);
        $name =   Str::studly($name);
        if(str_starts_with($name, $prefix)){
            $name = Str::replaceFirst($prefix, '', $name);
        }
        return $name;
    }


    /** 获取数据库字段 */
    protected function getTableField($name)
    {
        $res = [];
//        $columns = \DB::select('SHOW COLUMNS FROM `' . $name . '`');
        $databasename = \DB::getDatabaseName();
        $columns = \DB::select('SELECT * FROM `information_schema`.`columns`  WHERE TABLE_SCHEMA = "'.$databasename.'" AND table_name = "'.$name.'"  ORDER BY ORDINAL_POSITION;');
        foreach ($columns as $vv) {

            if(in_array($vv->COLUMN_NAME, ['id', 'created_at', 'updated_at', 'deleted_at', 'is_valid' ])){
                continue;
            }
            $result = [];
            $result['name'] = $vv->COLUMN_NAME;
            $result['text'] = empty($vv->COLUMN_COMMENT) ? $vv->COLUMN_NAME: $vv->COLUMN_COMMENT;
            $result['verify'] = $vv->IS_NULLABLE == 'NO' ? 'required' : '' ;
            $result['value'] = $vv->COLUMN_DEFAULT;
            if (strpos($vv->DATA_TYPE, "int") !== false)
                $type = 'number';
            else{
                $type = 'text';
            }
            $result['type'] = $type;
            $res[] = $result;
        }
        return $res;
    }


    /** 获取提货模板 */
    protected function getTemplate($type, $table)
    {
        $field = $this->getTableField($table);
        switch ($type){
            case 'index':
                $str = <<<'EOT'
                    ,{field:'{{name}}', title:'{{text}}', width:150 }

EOT;
                $result = array_map(function ($item)use($str){
                    $str = str_replace('{{name}}', $item['name'], $str);
                    $str = str_replace('{{text}}', $item['text'], $str);
                    return $str;
                },$field);
                return implode('', $result);
                break;
            case 'form':
                $str = <<<'EOT'
        <div class="layui-form-item">
            <label class="layui-form-label">{{text}}</label>
            <div class="layui-input-block">
                <input type="{{type}}" name="{{name}}" lay-verify="{{verify}}" value="{{value}}" autocomplete="off" placeholder="{{text}}" class="layui-input">
            </div>
        </div>

EOT;
                $result = array_map(function ($item)use($str){
                    $str = str_replace('{{name}}', $item['name'], $str);
                    $str = str_replace('{{text}}', $item['text'], $str);
                    $str = str_replace('{{type}}', $item['type'], $str);
                    $str = str_replace('{{verify}}', $item['verify'], $str);
                    $str = str_replace('{{value}}', $item['value'], $str);
                    return $str;
                },$field);
                return implode('', $result);
                break;
        }
    }






}
